package com.jh.hts_jdk.item;

import java.util.Arrays;
import java.util.stream.IntStream;

public class HolePlate extends DataFrame<Character,Integer>{

    public static final Character[] ROW_LIST_96 = new Character[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };
    public static final Integer[] COL_LIST_96 = new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

    public static final Character[] ROW_LIST_384 = new Character[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P' };
    public static final Integer[] COL_LIST_384 = new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 };

    private static Character[] Szie2RowList(int size){
        Character[] row_list;
        switch (size) {
            case 96:
                row_list = Arrays.copyOf(ROW_LIST_96, ROW_LIST_96.length);
                break;
            case 384:
                row_list = Arrays.copyOf(ROW_LIST_384, ROW_LIST_384.length);
                break;
            default:
                row_list = new Character[0];
                break;
        }
        return row_list;
    }

    private static Integer[] Szie2ColList(int size) {
        Integer[] col_list;
        switch (size) {
            case 96:
                col_list = Arrays.copyOf(COL_LIST_96, COL_LIST_96.length);
                break;
            case 384:
                col_list = Arrays.copyOf(COL_LIST_384, COL_LIST_384.length);
                break;
            default:
                col_list = new Integer[0];
                break;
        }
        return col_list;
    }

    
    private Point current_point = new Point();
    
    public HolePlate(int size) {
        super(Szie2RowList(size), Szie2ColList(size), 0);
    }

    public void moveTo(int i, int j){
        current_point.row_index = i;
        current_point.col_index = j;
    }

    public void nextCol(){
        current_point.col_index += 1;
        if (current_point.col_index >= getDimension()[1]) {
            current_point.row_index += 1;
            current_point.col_index = 0;
        }
    }

    public void nextRow(){
        current_point.row_index += 1;
        if(current_point.row_index >= getDimension()[0]){
            current_point.col_index += 1;
            current_point.row_index = 0;
        }
    }

    private boolean pointOutOfBound(Point p){
        int[] dimension = getDimension();
        if (current_point.row_index < 0 || current_point.row_index >= dimension[0] || current_point.col_index < 0 || current_point.col_index >= dimension[1]) {
            return true;
        }
        return false;
    }

    public boolean setWell(Object v){
        if(pointOutOfBound(current_point)){
            return false;
        }
        setValue(current_point.row_index, current_point.col_index, v);
        return true;
    }

    public boolean putByRow(Object v){
        boolean b = setWell(v);
        nextCol();
        return b;
    }

    public boolean putByCol(Object v){
        boolean b = setWell(v);
        nextRow();
        return b;
    }

    public int[] getPoint(){
        return new int[]{current_point.row_index, current_point.col_index};
    }

    public String getPointStr(int i, int j){
        
        return String.valueOf(this.getRowName()[i]) + String.valueOf(this.getColName()[j]);
    }

    public String getPointStr(){
        return getPointStr(current_point.row_index, current_point.col_index);
    }

    public Object getWell(){
        if (pointOutOfBound(current_point)) {
            return null;
        }
        return getValue(current_point.row_index, current_point.col_index);
    }

    public Object getByRow(){
        Object v = getWell();
        nextCol();
        return v;
    }

    public Object getByCol(){
        Object v = getWell();
        nextRow();
        return v;
    }

    public DataFrame<Integer,String> ToListByRow(){
        int [] plate_dimension = getDimension();
        Integer[] list_row_name = IntStream.rangeClosed(1, plate_dimension[0]*plate_dimension[1]).boxed().toArray(Integer[]::new);
        String[] list_col_name = new String[]{"plate", "hole", "value"};
        DataFrame<Integer,String> list_df = new DataFrame<>(list_row_name, list_col_name, null);
        moveTo(0, 0);
        Object v;
        int list_index = 0;
        while ((v = getWell())!=null) {
            list_df.setRow(list_index, new Object[] { this.name, getPointStr(), v });
            nextCol();
            list_index ++;
        }
        return list_df;
    }

    public DataFrame<Integer, String> ToListByCol() {
        int[] plate_dimension = getDimension();
        Integer[] list_row_name = IntStream.rangeClosed(1, plate_dimension[0] * plate_dimension[1]).boxed().toArray(Integer[]::new);
        String[] list_col_name = new String[] { "plate", "hole", "value" };
        Object data = null;
        DataFrame<Integer, String> list_df = new DataFrame<>(list_row_name, list_col_name, data);
        moveTo(0, 0);
        Object v;
        int list_index = 0;
        while ((v = getWell()) != null) {
            list_df.setRow(list_index, new Object[] { this.name, getPointStr(), v });
            nextRow();
            list_index++;
        }
        return list_df;
    }

    @Override
    @Deprecated
    public void appendRow(Character row_name, Object[] value) {

    }

    @Override
    @Deprecated
    public void appendCol(Integer col_name, Object[] value) {

    }

}


/**
 * InnerHolePlate
 */
class Point {
    public int row_index;
    public int col_index;
    
    public Point(){

    }
}